package com.xinzhidi.web.bigscreen.service.impl;


import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.xinzhidi.common.constant.AgreementConstants;
import com.xinzhidi.common.core.redis.RedisCache;
import com.xinzhidi.common.utils.WeatherUtil;
import com.xinzhidi.web.bigscreen.domain.bo.BigScreenBo;
import com.xinzhidi.web.bigscreen.domain.po.LineChartPo;
import com.xinzhidi.web.bigscreen.domain.vo.*;
import com.xinzhidi.web.bigscreen.mapper.BigScreenMapper;
import com.xinzhidi.web.bigscreen.service.IBigScreenService;
import com.xinzhidi.web.build.domain.BuildUnit;
import com.xinzhidi.web.build.service.IBuildUnitService;
import com.xinzhidi.web.city.domain.City;
import com.xinzhidi.web.city.mapper.CityMapper;
import com.xinzhidi.web.ctw.domain.po.TemperaturePo;
import com.xinzhidi.web.ctw.service.HouseholdTemperatureService;
import com.xinzhidi.web.netty.entity.householdHeat.ReadData;
import org.apache.commons.compress.utils.Lists;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

@Service
public class BigScreenServiceImpl implements IBigScreenService {
    @Autowired
    private BigScreenMapper bigScreenMapper;

    @Autowired
    private CityMapper cityMapper;

    @Autowired
    private IBuildUnitService buildUnitService;

    @Autowired
    private RedisCache redisCache;

    @Autowired
    private HouseholdTemperatureService householdTemperatureService;

    @Override
    public List<DeviceStatisticsVo> deviceStatistics(BigScreenBo bigScreenBo) {
        return bigScreenMapper.deviceStatistics(bigScreenBo);
    }

    @Override
    public DataOverviewVo dataOverview(BigScreenBo bigScreenBo) {
        DataOverviewVo overview = bigScreenMapper.dataOverview(bigScreenBo);
        List<BuildInfoListVo> buildInfoListVo = bigScreenMapper.buildInfoList(bigScreenBo);
        DataOverviewVo dataOverviewVo = new DataOverviewVo();
        dataOverviewVo.setTotalHousehold(overview.getTotalHousehold());
        dataOverviewVo.setWarningCount(overview.getWarningCount());
        dataOverviewVo.setTotalHeatArea(overview.getTotalHeatArea());
        dataOverviewVo.setBuildInfoList(buildInfoListVo);
        return dataOverviewVo;

    }

    @Override
    public WarningInfoVo warningInformation(BigScreenBo bigScreenBo) {
        WarningInfoVo vo = bigScreenMapper.warningInformation(bigScreenBo);
        return vo;
    }

    @Override
    public LineChartVo lineChart(LineChartPo po) {
        LineChartVo lineChartVo = new LineChartVo();
        if (po.getBuildId() == null) {
            return lineChartVo;
        }

        List<LineChartDataVo> lineChartDataVos = bigScreenMapper.lineChart(po);

        if (CollectionUtils.isNotEmpty(lineChartDataVos)) {
            List<String> xAxis = Lists.newArrayList();
            List<BigDecimal> waterSupplyTemperature = Lists.newArrayList();
            List<BigDecimal> returnWaterTemperatures = Lists.newArrayList();
            List<BigDecimal> temperatures = Lists.newArrayList();
            List<BigDecimal> thermalPowers = Lists.newArrayList();
            for (LineChartDataVo dataVo : lineChartDataVos) {
                if (dataVo == null) {
                    continue;
                }
                xAxis.add(dataVo.getTime());
                waterSupplyTemperature.add(dataVo.getWaterSupplyTemperature());
                returnWaterTemperatures.add(dataVo.getReturnWaterTemperature());
                temperatures.add(dataVo.getTemperature());
                thermalPowers.add(dataVo.getThermalPower());
            }
            lineChartVo.setXAxis(xAxis);
            lineChartVo.setWaterSupplyTemperatures(waterSupplyTemperature);
            lineChartVo.setReturnWaterTemperatures(returnWaterTemperatures);
            lineChartVo.setTemperatures(temperatures);
            lineChartVo.setThermalPowers(thermalPowers);
        }
        return lineChartVo;
    }

    @Override
    public IndexStatisticsVo indexStatistics(Long plotId) {
        IndexStatisticsVo vo = new IndexStatisticsVo();

        //获取总流量
        BigDecimal totalFlow = bigScreenMapper.getTotalFlow(plotId);
        BigDecimal unitFlowArea = BigDecimal.ZERO;


        //获取日消耗
        List<Map<String , Object>> dailyConsumptionMapList =  bigScreenMapper.getDailyConsumption(plotId , AgreementConstants.AgreementType.UNIT_HEAT_METER , 1 , null);
        if(CollectionUtils.isEmpty(dailyConsumptionMapList)){
            dailyConsumptionMapList  = bigScreenMapper.getDailyConsumption(plotId , AgreementConstants.AgreementType.HOUSEHOLD_HEAT_METER , 1 , null);
        }

        //今日热量消耗
        BigDecimal todayConsumption = BigDecimal.ZERO;
        //昨日热量消耗
        BigDecimal yesterdayConsumption = BigDecimal.ZERO;
        BigDecimal dailyConsumption;
        if(CollectionUtils.isNotEmpty(dailyConsumptionMapList)){
            todayConsumption = dailyConsumptionMapList.stream()
                    .filter(x -> x.get("id") != null)
                    .map(x -> new BigDecimal(String.valueOf(x.get("value")))).reduce(BigDecimal.ZERO,BigDecimal::add);
            List<Long> equipmentIds = dailyConsumptionMapList.stream()
                    .filter(x -> x.get("id") != null)
                    .map(x -> Long.valueOf(String.valueOf(x.get("id")))).collect(Collectors.toList());
            List<Map<String , Object>> yesterdayConsumptionMapList = bigScreenMapper.getDailyConsumption(plotId , AgreementConstants.AgreementType.UNIT_HEAT_METER , null , equipmentIds);
            if(CollectionUtils.isNotEmpty(yesterdayConsumptionMapList)){
                yesterdayConsumption = yesterdayConsumptionMapList.stream().map(x -> new BigDecimal(String.valueOf(x.get("value")))).reduce(BigDecimal.ZERO,BigDecimal::add);
            }
        }
        dailyConsumption = todayConsumption.subtract(yesterdayConsumption).setScale(2,BigDecimal.ROUND_HALF_UP);

        //获取单位面积热指标
        BigDecimal unitHeatArea = BigDecimal.ZERO;
        //1：获取供热面积
        LambdaQueryWrapper<BuildUnit> queryWrapper = Wrappers.lambdaQuery();
        queryWrapper.eq(BuildUnit::getLotId, plotId);
        List<BuildUnit> buildUnits = buildUnitService.list(queryWrapper);
        //2：获取供热面积总和
        BigDecimal totalHeatArea = buildUnits.stream()
                .filter(buildUnit -> buildUnit.getHeatArea() != null)
                .map(BuildUnit::getHeatArea)
                .reduce(BigDecimal.ZERO, BigDecimal::add);
        if (totalHeatArea != null && totalHeatArea.compareTo(BigDecimal.ZERO) > 0) {
            unitHeatArea = dailyConsumption.divide(totalHeatArea, 2, BigDecimal.ROUND_HALF_UP);
            unitFlowArea = totalFlow.divide(totalHeatArea, 2, BigDecimal.ROUND_HALF_UP);
        }

        ReadData readData = bigScreenMapper.getHeatData(plotId);
        if (readData != null) {
            vo.setWaterSupplyTemperature(readData.getWaterSupplyTemperature());
            vo.setReturnWaterTemperature(readData.getReturnWaterTemperature());
        }
        //获取平均室温
        TemperaturePo po = new TemperaturePo();
        po.setPlotId(plotId);
        BigDecimal temperature = householdTemperatureService.getAvgTemperature(po);
        vo.setRoomTemperature(temperature != null ? temperature.setScale(2, BigDecimal.ROUND_HALF_UP) : BigDecimal.ZERO);
        vo.setDailyConsumption(dailyConsumption);
        vo.setUnitHeatArea(unitHeatArea != null ? unitHeatArea.setScale(2, BigDecimal.ROUND_HALF_UP) : BigDecimal.ZERO);
        vo.setUnitFlowArea(unitFlowArea != null ? unitFlowArea.setScale(2, BigDecimal.ROUND_HALF_UP) : BigDecimal.ZERO);
        return vo;
    }

    @Override
    public List<Integer> warnType(Long plotId) {
        List<Integer> list = Lists.newArrayList();
        List<WarnTypeVo> warnTypeVos = bigScreenMapper.warnType(plotId);
        if (CollectionUtils.isEmpty(warnTypeVos)) {
            return list;
        }
        //通讯异常
        Integer tx;
        //回温异常
        Integer hw;
        //供温异常
        Integer gw;
        //室温异常
        Integer sw;
        //流量异常
        Integer ll;

        //开度异常
        Integer kd;
        //获取warnTypeVos里remark字段包含通讯的数量
        tx = warnTypeVos.stream().filter(warnTypeVo -> warnTypeVo.getRemark().contains("通讯")).collect(Collectors.toList()).size();
        hw = warnTypeVos.stream().filter(warnTypeVo -> warnTypeVo.getRemark().contains("】回水温度")).collect(Collectors.toList()).size();
        gw = warnTypeVos.stream().filter(warnTypeVo -> warnTypeVo.getRemark().contains("供回水温度")).collect(Collectors.toList()).size();
        sw = warnTypeVos.stream().filter(warnTypeVo -> warnTypeVo.getRemark().contains("室内温度")).collect(Collectors.toList()).size();
        ll = warnTypeVos.stream().filter(warnTypeVo -> warnTypeVo.getRemark().contains("流量")).collect(Collectors.toList()).size();
        kd = warnTypeVos.stream().filter(warnTypeVo -> warnTypeVo.getRemark().contains("开度")).collect(Collectors.toList()).size();
        list.add(tx);
        list.add(hw);
        list.add(gw);
        list.add(sw);
        list.add(ll);
        list.add(kd);

        return list;
    }

    @Override
    public EnergyDataVo energyData(BigScreenBo bigScreenBo) {
        EnergyDataVo energyDataVo = new EnergyDataVo();
        List<EnergyDataListVo> energyDataListVo = bigScreenMapper.energyData(bigScreenBo);
        if (CollectionUtils.isEmpty(energyDataListVo)) {
            return energyDataVo;
        }
        List<String> buildList = energyDataListVo.stream().map(EnergyDataListVo::getBuildName).collect(Collectors.toList());
        List<BigDecimal> heatOrColdList = bigScreenMapper.getHeatOrCold(bigScreenBo);
        List<Integer> valveOpenList = energyDataListVo.stream().map(EnergyDataListVo::getValveOpen).collect(Collectors.toList());
        List<BigDecimal> thermalPowerList = energyDataListVo.stream().map(EnergyDataListVo::getThermalPower).collect(Collectors.toList());
        energyDataVo.setBuildList(buildList);
        energyDataVo.setHeatOrColdList(heatOrColdList);
        energyDataVo.setValveOpenList(valveOpenList);
        energyDataVo.setThermalPowerList(thermalPowerList);
        return energyDataVo;
    }

    @Override
    public String getWeather(String cityCode) {
        String token = "f9f212e1996e79e0e602b08ea297ffb0";
        String path = "/whapi/json/alicityweather/forecast15days";
        String cityId = getCityId(cityCode);
        String key = cityId + "15DAY";
        return checkCache(cityId, token, key, path);
    }

    @Override
    public String getRealTime(String cityCode) {
        String token = "008d2ad9197090c5dddc76f583616606";
        String path = "/whapi/json/alicityweather/forecast24hours";
        String cityId = getCityId(cityCode);
        String key = cityId + "24H";
        return checkCache(cityId, token, key, path);
    }

    @Override
    public String weatherWarning(String cityCode) {
        String token = "7ebe966ee2e04bbd8cdbc0b84f7f3bc7";
        String path = "/whapi/json/alicityweather/alert";
        String cityId = getCityId(cityCode);
        String key = cityId + "WARNING";
        return checkCache(cityId, token, key, path);
    }

    /**
     * 判断 缓存中是否有相关天气信息 有就返回缓存中的天气信息，没有就去查询返回并且缓存一小时
     *
     * @param lat   纬度
     * @param lon   经度
     * @param token token
     * @return
     */
    public String checkCache(String cityId, String token, String key, String path) {
        if (redisCache.hasKey(key)) {
            return redisCache.getCacheObject(key);
        } else {
            String weatherInfo = WeatherUtil.getWeather(cityId, token, path);
            redisCache.setCacheObject(key, weatherInfo, 60, TimeUnit.MINUTES);
            return weatherInfo;
        }
    }

    /**
     * 根据城市编码获取城市id
     *
     * @param cityCode
     * @return
     */
    public String getCityId(String cityCode) {
        LambdaQueryWrapper<City> wrapper = Wrappers.lambdaQuery();
        wrapper.eq(City::getId, cityCode).select(City::getCityId);
        City city = cityMapper.selectOne(wrapper);
        return String.valueOf(city.getCityId());
    }
}
